package com.apes.fn.scm.internal.help.service.voucher.retail;

import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailReturn.RetailReturn;
import com.apes.fn.server.servicePlan.model.ClientInvoiceRules;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanRepository;
import com.apes.fn.server.servicePlan.service.ClientInvoiceRulesService;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author wuq
 * @Time 2023-3-22 11:49
 * @Description
 */
@Service
public class UnitClientReturnVoucherService extends DomainService {

    @Autowired
    private ClientInvoiceRulesService clientInvoiceRulesService;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private InventoryService inventoryService;

    public void process(RetailReturn retailReturn) {
        if (StringUtils.isEmpty(retailReturn.getSaleOrder().getSource())) return;
        // 检查是否为单位客户挂账
        ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne( retailReturn.getSaleOrder().getSource());
        if (Objects.isNull(servicePlan)) return;
        List<ServicePlanItem> unitClientPlanItems = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> Objects.nonNull(servicePlanItem.getUnitClient()))
                .collect(Collectors.toList());
        if (unitClientPlanItems.size() == 0) return;

        // 查询单位客户挂账规则
        PartyRole unitClient = unitClientPlanItems.get(0).getUnitClient();
        ClientInvoiceRules clientInvoiceRule = clientInvoiceRulesService.findClientInvoiceRules(retailReturn.getDept(), unitClient);
        if (Objects.isNull(clientInvoiceRule))
            throw new RuntimeException("没有找到 (" + unitClient.getId() + ") " + unitClient.getName() + "的开票规则，请检查！");

        // 判断是否为开票公司
        if (clientInvoiceRule.getCompany().getId().equals(retailReturn.getCompany().getId())) {
            // 为开票公司
            returnProcess(retailReturn, clientInvoiceRule.getCustomer());
        } else {
            // 非开票公司
            crossReturnProcess(retailReturn, clientInvoiceRule);
        }
    }

    private void returnProcess(RetailReturn retailReturn, PartyRole customer) {
        // 由于在前面生成零售退回凭证时，已经生成了销售退回凭证，这里直接退采购凭证，以及生成负数账单
        Voucher saleReturnVoucher = voucherRepository.findOne(
                        JpaDsl.toCriteriaByEq("sourceBusinessType", retailReturn.getInnerBusinessType(),
                                "source", retailReturn.getId(), "origin", retailReturn.getId(), "voucherType", "CUSTOMER_SALE",
                                "partner",customer.getParty().getPartyRoleByType("Customer")))
                .orElseThrow(() -> new RuntimeException("单位客户退回时，未找到：" + retailReturn.getSaleOrder().getId() + " 的业务凭证！"));

        // 生成负数的账单
        Invoice invoice = invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(saleReturnVoucher))));
        if (StringUtils.isEmpty(invoice.getCustomerExpand())){
            invoice.setCustomerExpand(retailReturn.getCustomerExpand().getId());
        }

        // 退采购
        returnPurchaseVoucher(retailReturn.getCompany(), saleReturnVoucher, retailReturn);
    }

    private void crossReturnProcess(RetailReturn retailReturn, ClientInvoiceRules clientInvoiceRule){
        // 第一步：退门店的自采凭证，以及销售账单
        returnProcess(retailReturn, clientInvoiceRule.getCompany());

        // 第二步：退开票公司的销售
        PartyRole partner = clientInvoiceRule.getCustomer().getParty().getPartyRoleByType("Customer");
        RetailOrderItem retailOrderItem = retailReturn.getSaleItems().iterator().next().getRetailOrderItem();
        Voucher originStoreVoucher = voucherRepository.findSaleVoucherByCompanyAndItemSource(clientInvoiceRule.getCompany(), partner, retailOrderItem.getId());
        returnSaleVoucher(retailReturn, originStoreVoucher);

        // 第三步：退开票公司的采购
        Voucher returnPurchaseVoucher = returnPurchaseVoucher(retailReturn.getCompany(), originStoreVoucher, retailReturn);
        createFixedOriginNumberInvoice(retailReturn, returnPurchaseVoucher);
    }

    private Voucher returnPurchaseVoucher(PartyRole supplier, Voucher originSaleVoucher, RetailReturn retailReturn){
        Voucher voucher = new Voucher();
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.PURCHASE_RETURN);

        ReflectUtil.copy(originSaleVoucher, voucher, "dept", "company");
        voucher.setPartner(supplier.getParty().getPartyRoleByType("Supplier"));
        voucher.setClerk(retailReturn.getClerk());

        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有经销
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：采购

        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());

        voucher.setVoucherItems(
                retailReturn.getSaleItems().stream().map( retailReturnItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    voucherItem.setProduct(retailReturnItem.getProduct());
                    voucherItem.setUom(retailReturnItem.getUom());
                    voucherItem.setProductQty(-1.00 * retailReturnItem.getProductUomQty());
                    voucherItem.setOriginItemId(String.valueOf(retailReturnItem.getId()));
                    voucherItem.setSourceItemId(String.valueOf(retailReturnItem.getId()));
                    voucherItem.setOwner(originSaleVoucher.getCompany());

                    //找到原销售凭证的明细行
                    VoucherItem saleVoucherItem = originSaleVoucher.getVoucherItems().stream()
                            .filter( saleItem -> saleItem.getProduct().getId().equals(retailReturnItem.getProduct().getId()) )
                            .findFirst()
                            .orElseThrow(() -> new RuntimeException("生成单位客户返厂凭证时，根据商品编码没有找到对应的凭证明细，" +
                                    "商品编码："+ retailReturnItem.getProduct().getId() +"，凭证编码："+ originSaleVoucher.getId()));

                    // 获取原销售批次
                    VoucherInventory voucherInventory = voucherInventoryRepository.findAll(
                                    JpaDsl.toCriteriaByEq("voucher.id", originSaleVoucher.getId(), "voucherItem", saleVoucherItem))
                            .stream().findFirst().get();

                    InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();
                    voucherItem.setInventoryBatch(inventoryBatch);
                    voucherItem.setPriceUnit(inventoryBatch.getTaxCostPrice());
                    voucherItem.setSupplier(inventoryBatch.getSupplier());
                    voucherItem.setTax(inventoryBatch.getTax());

                    //  增加（减少）冻结数量
                    inventoryService.changeFrostQty(inventoryBatch, retailReturnItem.getUom(), retailReturnItem.getProductUomQty(), inventoryBatch.getCompany(),
                            retailReturn.getInnerBusinessType(), retailReturn.getId(), retailReturnItem.getId(), "生成零售单位客户挂账返厂凭证");

                    return voucherItem;
                }).collect(Collectors.toSet()));

        Voucher newVoucher = invoke("voucher.create", MapUtil.mapped(voucher));
        return newVoucher;
    }


    private void returnSaleVoucher(RetailReturn retailReturn, Voucher originSaleVoucher){
        Voucher voucher = new Voucher();
        // 销售退回必填字段
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.SALE_RETURN);
        voucher.setVoucher(originSaleVoucher);

        ReflectUtil.copy(originSaleVoucher, voucher, "dept", "company", "partner");
        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有经销
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：采购

        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());
        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        voucher.setClassification(VoucherType.UNIT_CLIENT_CROSS_RETURN);

        voucher.setVoucherItems(
                originSaleVoucher.getVoucherItems().stream().map(saleItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    voucherItem.setProduct(saleItem.getProduct());
                    voucherItem.setTax(saleItem.getTax());
                    voucherItem.setOwner(saleItem.obtainOwner());
                    voucherItem.setUom(saleItem.getUom());          // 设置为销售的单位以及数量
                    voucherItem.setProductQty(-1 * Math.abs(saleItem.getProductQty()));
                    voucherItem.setPriceUnit(saleItem.getPriceUnit());      // 默认为退货单价
                    voucherItem.setOriginItemId(String.valueOf(saleItem.getId()));
                    voucherItem.setSourceItemId(String.valueOf(saleItem.getId()));
                    voucherItem.setOwner(originSaleVoucher.getCompany());

                    voucherItem.setVoucherItem(saleItem);   // 退回时传入明细行号

                    return voucherItem;
                }).collect(Collectors.toSet()));

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createFixedOriginNumberInvoice(retailReturn, voucher);
    }

    private void createFixedOriginNumberInvoice(RetailReturn retailReturn, Voucher voucher) {
        // 获取 invoice Mapping 文件
        Map m = invoke("voucher.flow.invoice", MapUtil.mapped(voucher));

        m.put("origin", retailReturn.getSaleOrder().getSource());
        m.put("originBusinessType", retailReturn.getSaleOrder().getSourceBusinessType());

        // 生成账单
        invoke("invoice.create", m);
    }

}
